package orgInfo

// 管理员使用resmgmt的操作
import (
	"fmt"
	mb "github.com/hyperledger/fabric-protos-go/msp"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp"
	lcpackager "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/lifecycle"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
	"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/policydsl"
)

// 组织的链码生命周期
// InstallCC 安装链码
func (o *OrgInfo) InstallCC(fabSDK *fabsdk.FabricSDK, peerUrl string, channelId string, label string, ccPkg []byte) error {
	installCCReq := resmgmt.LifecycleInstallCCRequest{
		Label:   label,
		Package: ccPkg,
	}
	// 获取packageID
	packageID := lcpackager.ComputePackageID(installCCReq.Label, installCCReq.Package)
	// 获取节点
	peer, err := o.GetPeerByUrl(fabSDK, peerUrl)
	if err != nil {
		return fmt.Errorf("InstallCC err:%v", err)
	}
	// 获取该组织管理员的resmgmt
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return fmt.Errorf("InstallCC err:%v", err)
	}
	// 检查该节点是否已经安装该链码
	flag, _ := o.CheckInstalled(packageID, peer, resmgmtClient)
	if flag {
		return fmt.Errorf("InstallCC err:已安装该链码.")
	}
	if _, err := resmgmtClient.LifecycleInstallCC(installCCReq, resmgmt.WithTargets(peer), resmgmt.WithRetry(retry.DefaultResMgmtOpts)); err != nil {
		return fmt.Errorf("LifecycleInstallCC error: %v", err)
	}
	return nil
}

// CheckInstalled 检查是否安装packageID链码
func (o *OrgInfo) CheckInstalled(packageID string, peer fab.Peer, client *resmgmt.Client) (bool, error) {
	flag := false
	resp1, err := client.LifecycleQueryInstalledCC(resmgmt.WithTargets(peer))
	if err != nil {
		return flag, fmt.Errorf("LifecycleQueryInstalledCC error: %v", err)
	}
	for _, t := range resp1 {
		if t.PackageID == packageID {
			flag = true
		}
	}
	return flag, nil
}

// approveCC 为组织认可链代码
func (o *OrgInfo) ApproveCC(fabSDK *fabsdk.FabricSDK, packageID string, ccName, ccVersion string, sequence int64, channelID string, ordererEndpoint string, mspIDs []string) error {
	// 背书策略
	ccPolicy := policydsl.SignedByNOutOfGivenRole(int32(len(mspIDs)), mb.MSPRole_PEER, mspIDs)
	approveCCReq := resmgmt.LifecycleApproveCCRequest{
		Name:              ccName,
		Version:           ccVersion,
		PackageID:         packageID,
		Sequence:          sequence,
		EndorsementPlugin: "escc",
		ValidationPlugin:  "vscc",
		SignaturePolicy:   ccPolicy,
		InitRequired:      true,
	}
	// 获取该组织所有peer节点
	orgPeers, err := o.GetPeers(fabSDK)
	fmt.Printf(">>> chaincode approved by %s peers:\n", o.OrgName)
	for _, p := range orgPeers {
		fmt.Printf("	%s\n", p.URL())
	}
	if err != nil {
		return fmt.Errorf("approveCC error: %v", err)
	}
	//获取管理员资源管理客户端
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return fmt.Errorf("approveCC error: %v", err)
	}
	if _, err := resmgmtClient.LifecycleApproveCC(channelID, approveCCReq, resmgmt.WithTargets(orgPeers...), resmgmt.WithOrdererEndpoint(ordererEndpoint), resmgmt.WithRetry(retry.DefaultResMgmtOpts)); err != nil {
		return fmt.Errorf("approveCC error: %v", err)
	}
	return nil
}

// 查询链码批准情况
func (o *OrgInfo) CheckCCCommitReadiness(fabSDK *fabsdk.FabricSDK, ccName, ccVersion string, sequence int64, channelID string, mspIDs []string) (approvals map[string]bool, err error) {
	// 默认背书策略
	ccPolicy := policydsl.SignedByNOutOfGivenRole(int32(len(mspIDs)), mb.MSPRole_PEER, mspIDs)
	req := resmgmt.LifecycleCheckCCCommitReadinessRequest{
		Name:              ccName,
		Version:           ccVersion,
		EndorsementPlugin: "escc",
		ValidationPlugin:  "vscc",
		SignaturePolicy:   ccPolicy,
		Sequence:          sequence,
		InitRequired:      true,
	}
	// 获取该组织所有peer节点
	orgPeers, err := o.GetPeers(fabSDK)
	for _, p := range orgPeers {
		fmt.Printf("	%s\n", p.URL())
	}
	if err != nil {
		return nil, fmt.Errorf("CheckCCCommitReadiness error: %v", err)
	}
	//获取管理员资源管理客户端
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return nil, fmt.Errorf("CheckCCCommitReadiness error: %v", err)
	}
	// 查询
	response, err := resmgmtClient.LifecycleCheckCCCommitReadiness(channelID, req, resmgmt.WithTargets(orgPeers...))
	if err != nil {
		return nil, fmt.Errorf("CheckCCCommitReadiness error: %v", err)
	}
	return response.Approvals, nil
}

// commitCC 提交链码  只需要一个提交就行
func (o *OrgInfo) CommitCC(fabSDK *fabsdk.FabricSDK, ccName, ccVersion string, sequence int64, channelID string, ordererEndpoint string, mspIDs []string) error {
	//获取管理员资源管理客户端
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return fmt.Errorf("commitCC error: %v", err)
	}
	// 构建交易提案
	ccPolicy := policydsl.SignedByNOutOfGivenRole(int32(len(mspIDs)), mb.MSPRole_PEER, mspIDs)
	req := resmgmt.LifecycleCommitCCRequest{
		Name:              ccName,
		Version:           ccVersion,
		Sequence:          sequence,
		EndorsementPlugin: "escc",
		ValidationPlugin:  "vscc",
		SignaturePolicy:   ccPolicy,
		InitRequired:      true,
	}
	// 提交链码
	_, err = resmgmtClient.LifecycleCommitCC(channelID, req, resmgmt.WithOrdererEndpoint(ordererEndpoint), resmgmt.WithRetry(retry.DefaultResMgmtOpts))
	if err != nil {
		return fmt.Errorf("commitCC error: %v", err)
	}
	return nil
}

// QueryCommittedCC 查询通道上链码提交情况
func (o *OrgInfo) QueryCommittedCC(fabSDK *fabsdk.FabricSDK, channelId string) ([]resmgmt.LifecycleChaincodeDefinition, error) {
	//获取管理员资源管理客户端
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return nil, fmt.Errorf("commitCC error: %v", err)
	}
	resp, err := resmgmtClient.LifecycleQueryCommittedCC(channelId, resmgmt.LifecycleQueryCommittedCCRequest{})
	return resp, nil
}

// 创建通道

// CreatChannel 创建通道--- 使用ordererInfo来创建
//func (o *OrgInfo) CreatChannel(fabSDK *fabsdk.FabricSDK, channelId string, channelCfgPath string, ordererEndpoint string) error {
//	fmt.Println("使用org1的管理员身份创建通道")
//	//获取管理员资源管理客户端
//	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
//	if err != nil {
//		return fmt.Errorf("CreatChannel error: %v", err)
//	}
//	// 获取管理员签名
//	adminSigningIdentitie, err := o.GetSigningIdentity(fabSDK)
//	if err != nil {
//		return fmt.Errorf("CreatChannel error: %v", err)
//	}
//	// 创建通道
//	req := resmgmt.SaveChannelRequest{
//		ChannelID:         channelId,
//		ChannelConfigPath: channelCfgPath,
//		SigningIdentities: []msp.SigningIdentity{*adminSigningIdentitie},
//	}
//	if _, err := resmgmtClient.SaveChannel(req, resmgmt.WithOrdererEndpoint(ordererEndpoint)); err != nil {
//		return fmt.Errorf("CreatChannel error: %v", err)
//	}
//	return nil
//}

// UpdateAnchorPeerForNewChannel 更新锚节点配置-- 创建新通道时用到
func (o *OrgInfo) UpdateAnchorPeerForNewChannel(fabSDK *fabsdk.FabricSDK, channelID string, ordererEndpoint string) error {
	fmt.Println("使用每个org的管理员身份更新锚节点配置...")
	//获取管理员资源管理客户端
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return fmt.Errorf("UpdateAnchorPeerForNewChannel error: %v", err)
	}
	// 获取管理员签名
	adminSigningIdentitie, err := o.GetSigningIdentity(fabSDK)
	if err != nil {
		return fmt.Errorf("UpdateAnchorPeerForNewChannel error: %v", err)
	}
	// 构建交易提案
	req := resmgmt.SaveChannelRequest{
		ChannelID:         channelID,
		ChannelConfigPath: o.AnchorFile,
		SigningIdentities: []msp.SigningIdentity{*adminSigningIdentitie},
	}
	_, err = resmgmtClient.SaveChannel(req, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(ordererEndpoint))
	if err != nil {
		return fmt.Errorf("UpdateAnchorPeerForNewChannel err SaveChannel for anchor org %s error: %v", o.OrgName, err)
	}
	fmt.Println("使用每个org的管理员身份更新锚节点配置完成")
	return nil
}

// PeerJoinChannel 加入通道操作
func (o *OrgInfo) PeerJoinChannel(fabSDK *fabsdk.FabricSDK, channelID string, peerUrl string, ordererEndpoint string) error {
	//获取管理员资源管理客户端
	resmgmtClient, err := o.CreatResmgmt(fabSDK, o.AdminUser)
	if err != nil {
		return fmt.Errorf("PeerJoinChannel error: %v", err)
	}
	// 根据peerUrl获取peer实例
	peer, err := o.GetPeerByUrl(fabSDK, peerUrl)
	if err != nil {
		return fmt.Errorf("PeerJoinChannel error: %v", err)
	}
	// 加入通道
	if err := resmgmtClient.JoinChannel(channelID, resmgmt.WithTargets(peer), resmgmt.WithOrdererEndpoint(ordererEndpoint), resmgmt.WithRetry(retry.DefaultResMgmtOpts)); err != nil {
		return fmt.Errorf("PeerJoinChannel err ,%s %s failed to JoinChannel %s: %v", o.OrgName, peerUrl, channelID, err)
	}
	return nil
}
